/*
* 迭代器模式（Iterator Pattern）是 c++,Java 和 .Net 编程环境中非常常用的设计模式。
* 这种模式用于顺序访问集合对象的元素，不需要知道集合对象的底层表示。
*
* 迭代器模式属于行为型模式。
*
* 意图：提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
*
* 主要解决：不同的方式来遍历整个整合对象。
*
* 何时使用：遍历一个聚合对象。
*
* 如何解决：把在元素之间游走的责任交给迭代器，而不是聚合对象。
*
* 关键代码：定义接口：hasNext, next。
*
* 应用实例：C++的容器实现就有很多迭代器的例子
*
* 优点： 1、它支持以不同的方式遍历一个聚合对象。
*       2、迭代器简化了聚合类。
*       3、在同一个聚合上可以有多个遍历。
*       4、在迭代器模式中，增加新的聚合类和迭代器类都很方便，无须修改原有代码。
*
* 缺点：由于迭代器模式将存储数据和遍历数据的职责分离，增加新的聚合类需要对应增加新的迭代器类，类的个数成对增加，这在一定程度上增加了系统的复杂性。
*
* 使用场景： 1、访问一个聚合对象的内容而无须暴露它的内部表示。
*          2、需要为聚合对象提供多种遍历方式。
*          3、为遍历不同的聚合结构提供一个统一的接口。
*
* 注意事项：迭代器模式就是分离了集合对象的遍历行为，抽象出一个迭代器类来负责，这样既可以做到不暴露集合的内部结构，又可让外部代码透明地访问集合内部的数据。
*/

#include <string>
#include <vector>
#include <iostream>

/// 所有迭代器的基类，是一个抽象类
class Iterator
{
public:
    Iterator() {}
    virtual ~Iterator() {}
    virtual std::string First() = 0;
    virtual std::string Next() = 0;
    virtual std::string GetCur() = 0;
    virtual bool IsEnd() = 0;
};

class Aggregate
{
public:
    Aggregate() {}
    virtual ~Aggregate() {}
    virtual int Count() = 0;
    virtual void Push(const std::string& strValue) = 0;
    virtual std::string Pop(const int nIndex) = 0;
    virtual Iterator* CreateIterator() = 0;

};

/// 迭代器实例
class ConcreteIterator: public Iterator
{
public:
    ConcreteIterator(Aggregate* pAggregate)
        : Iterator()
        , m_nCurrent(0)
    {
        m_Aggregate = pAggregate;
    }
    std::string First()
    {
        return m_Aggregate->Pop(0);
    }
    std::string Next()
    {
        std::string strRet;
        m_nCurrent++;
        if (m_nCurrent < m_Aggregate->Count())
        {
            strRet = m_Aggregate->Pop(m_nCurrent);
        }
        return strRet;
    }
    std::string GetCur()
    {
        return m_Aggregate->Pop(m_nCurrent);
    }
    bool IsEnd()
    {
        return ((m_nCurrent >= m_Aggregate->Count()) ? true : false);
    }
private:
    int m_nCurrent;
    Aggregate* m_Aggregate;
};

class ConcreteAggregate: public Aggregate
{
public:
    ConcreteAggregate():m_pIterator(nullptr)
    {
        m_vecItems.clear();
    }
    ~ConcreteAggregate()
    {
        if (nullptr != m_pIterator)
        {
            delete m_pIterator;
            m_pIterator = nullptr;
        }
    }
    Iterator* CreateIterator()
    {
        if (nullptr == m_pIterator)
        {
            m_pIterator = new ConcreteIterator(this);
        }
        return m_pIterator;
    }
    int Count()
    {
        return m_vecItems.size();
    }
    void Push(const std::string& strValue)
    {
        m_vecItems.push_back(strValue);
    }
    std::string Pop(const int nIndex)
    {
        std::string strRet;
        if (nIndex < Count())
        {
            strRet = m_vecItems[nIndex];
        }
        return strRet;
    }
private:
    std::vector<std::string> m_vecItems;
    Iterator* m_pIterator;


};

int main()
{
    ConcreteAggregate* pName = nullptr;
    pName = new ConcreteAggregate();
    if (pName)
    {
        pName->Push("hello");
        pName->Push("word");
        pName->Push("cxue");
    }
    Iterator* iter = nullptr;
    iter = pName->CreateIterator();
    if (iter)
    {
        std::string strItem = iter->First();
        while (!iter->IsEnd())
        {
            std::cout << iter->GetCur() << " is ok" << std::endl;
            iter->Next();
        }
    }
    getchar();
    return 0;
}

